"""
This is the Interactive Outline Transport Protocol Daemon.

You can inherit from this class to create your own server and, um, stuff...

"""
import threading

from coffeetalk.protocol import ioml, requests, iotypes
from coffeetalk.server.configuration import startup
from coffeetalk.server import asyncserver, internalclient, ionode, iotree
from coffeetalk.utilities import authenticator, iologger

class IOTPD(object):
    
    def __init__(self):
        
        self.logger = iologger.IOLogger()
        self._env = iotypes.Environment('0.0.0.0','iotpd.py','Internal',str(id(self)),'0')
        self._systemtree = None
        self._iotrees = {}
        
        self.systemserver = None
        self.userserver = None        
        self.ioclient = None

        self.systemauthenticator = None
        
        self._authenticatorthread = None
        self._mainthread = None
        self._userthread = None
        
        self._initialize_iotrees()
        self._initialize_ioclient()
        
        self._startupconfig = None
        self.networkconfig = None
    
    def serve_forever(self,configpath=None,configstring=''):
        self._startupconfig = startup.StartupConfig(configstring=configstring,configpath=configpath,ioclient=self.ioclient)
                    
    def _initialize_iotrees(self):

        self._iotrees['System'] = iotree.IOTree(logger=self.logger)
        systemioml = ioml.IOML(iomlstring=startup.SYSTEMSTREAMS,nodetype=ionode.IONode,encoded=False)
        self._iotrees['System'].add_node(self._env, '/', systemioml.bodyelement)
        
        self._iotrees['Applications'] = iotree.IOTree(logger=self.logger)
        self._iotrees['Applications'].add_node(self._env,'/',ionode.IONode('Applications',{}))
        self._iotrees['Types'] = iotree.IOTree(logger=self.logger)
           
    def _initialize_ioclient(self):
        self.ioclient = internalclient.InternalClient(self._iotrees['System'])
        loggers = {'filelogging':iologger.IOFileLogger,'standardlogging':iologger.IOStdLogger,'streamlogger':iologger.IOStreamLogger}
        self.ioclient.subscribe(requests.Subscribe(path='/System/Config/Logging/',on_add=self._handle_loggers, on_error=self.handle_error,**loggers))
        self.ioclient.subscribe(requests.Subscribe(path='/System/Config/Servers/',on_add=self._handle_network_config, on_error=self.handle_error))
    
    def _handle_loggers(self,env,path,loggingobject,**kwargs):
        """handle_loggers(self,env,path,loggingobject,**kwargs"""
        name = loggingobject.name.lower()
        if hasattr(self.logger,name):
            self.logger.__setattr__(name,kwargs[name](loggingobject))
        self.logger.log_error(iologger.DEBUG,'0.0.0.0', self._env.username,self._env.group, iologger.current_function(), 'OK', '')
               
    def _handle_network_config(self,env,path,networkobject):
        
        self.networkconfig = networkobject
        
        self.systemserver = asyncserver.IOAsyncServer(networkobject.SystemBind.value,networkobject.SystemPort.value,'System',self._iotrees,self.logger)
        self.userserver = asyncserver.IOAsyncServer(networkobject.UserBind.value,networkobject.UserPort.value,'Users',self._iotrees,self.logger)
        
        self.systemauthenticator = authenticator.IOSystemAuthenticator(self.ioclient,networkobject.SystemPassword.value)
        self.ioclient.subscribe(requests.Subscribe(path='/System/Network/Clients/System/Login/',on_add=self.systemauthenticator.handle_login,on_error=self.handle_error))

        self.systemserver.make_socket()
        self._mainthread = threading.Thread(target=self.systemserver.main_loop,args=(0.01,))
        self._mainthread.setName('Main Server Thread')
        self._mainthread.start()
        
        self.userserver.make_socket()
        self._userthread = threading.Thread(target=self.userserver.main_loop,args=(0.1,))
        self._userthread.setName('User Server Thread')
        self._userthread.start()
        
        self.logger.log_error(iologger.DEBUG,'0.0.0.0', self._env.username,self._env.group, iologger.current_function(), 'OK', '')
        
    def handle_error(self,env,path,request,reason):
        print str(reason)
    
    def add_application(self,application):
        if isinstance(application,ionode.IONode):
            self._iotrees['Applications'].add_node(self._env,'/Applications/',application)
        else:
            print 'you suck'       
if __name__ == '__main__':
    iotpd = IOTPD()
    iotpd.serve_forever(configpath='./configuration/default_iotpd.conf')
        